using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Terra.Data.Context;
using Terra.Data.Entities.Identity;
using Terra.Data.Extensions;
using Terra.Data.Repository;

namespace Terra.Data.Repository.Identity
{
    /// <summary>
    /// 部门仓储实现
    /// </summary>
    public class DeptRepository : RepositoryBase<Dept, Guid>, IDeptRepository
    {
        private readonly TerraDbContext _terraDbContext;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="dbContext">数据库上下文</param>
        public DeptRepository(TerraDbContext dbContext) : base(dbContext)
        {
            _terraDbContext = dbContext;
        }

        #region 基础查询

        /// <summary>
        /// 获取部门树状结构所需数据
        /// </summary>
        /// <param name="status">状态过滤，为空则获取所有状态</param>
        /// <returns>按排序号排序的部门列表</returns>
        public async Task<List<Dept>> GetDeptTreeDataAsync(int? status = null)
        {
            var query = _terraDbContext.Depts.AsQueryable();

            // 如果指定了状态，进行过滤
            if (status.HasValue)
            {
                query = query.Where(d => d.Status == status.Value);
            }

            // 应用排序
            query = query.ApplyOrder(nameof(Dept.Sort));

            // 返回所有部门
            return await query.ToListAsync();
        }

        /// <summary>
        /// 获取部门下拉选择列表所需数据
        /// </summary>
        /// <param name="status">状态过滤，为空则获取所有状态</param>
        /// <returns>按排序号排序的部门列表</returns>
        public async Task<List<Dept>> GetDeptSelectDataAsync(int? status = null)
        {
            var query = _terraDbContext.Depts.AsQueryable();

            if (status.HasValue)
            {
                query = query.Where(d => d.Status == status.Value);
            }

            // 应用排序并返回结果
            return await query.ApplyOrder(nameof(Dept.Sort)).ToListAsync();
        }

        /// <summary>
        /// 获取指定部门及其所有子部门ID列表
        /// </summary>
        /// <param name="deptId">部门ID</param>
        /// <returns>部门ID列表，包含参数指定的部门ID和所有子部门ID</returns>
        public async Task<List<Guid>> GetDeptAndChildrenIdsAsync(Guid deptId)
        {
            var result = new List<Guid> { deptId };

            // 使用Path字段优化查询，避免递归
            var dept = await _terraDbContext.Depts.FindAsync(deptId);
            if (dept == null)
            {
                return result;
            }

            // 查询所有Path以当前部门Path开头的部门ID
            var childDepts = await _terraDbContext.Depts
                .Where(d => d.Path.StartsWith(dept.Path) && d.Id != deptId)
                .Select(d => d.Id)
                .ToListAsync();

            result.AddRange(childDepts);
            return result;
        }

        #endregion

        #region 数据验证

        /// <summary>
        /// 检查是否存在子部门
        /// </summary>
        /// <param name="deptId">部门ID</param>
        /// <returns>如果存在子部门返回true，否则返回false</returns>
        public async Task<bool> HasChildrenAsync(Guid deptId)
        {
            return await _terraDbContext.Depts.AnyAsync(d => d.ParentId == deptId);
        }

        /// <summary>
        /// 检查部门名称是否已存在
        /// </summary>
        /// <param name="name">部门名称</param>
        /// <param name="excludeId">排除的部门ID</param>
        /// <returns>如果名称已存在返回true，否则返回false</returns>
        public async Task<bool> ExistsByNameAsync(string name, Guid? excludeId = null)
        {
            var query = _terraDbContext.Depts.Where(d => d.Name == name);

            if (excludeId.HasValue)
            {
                query = query.Where(d => d.Id != excludeId.Value);
            }

            return await query.AnyAsync();
        }

        /// <summary>
        /// 检查部门编码是否已存在
        /// </summary>
        /// <param name="code">部门编码</param>
        /// <param name="excludeId">排除的部门ID</param>
        /// <returns>如果编码已存在返回true，否则返回false</returns>
        public async Task<bool> ExistsByCodeAsync(string code, Guid? excludeId = null)
        {
            if (string.IsNullOrWhiteSpace(code))
            {
                return false;
            }

            var query = _terraDbContext.Depts.Where(d => d.Code == code);

            if (excludeId.HasValue)
            {
                query = query.Where(d => d.Id != excludeId.Value);
            }

            return await query.AnyAsync();
        }

        #endregion

        #region 数据操作

        /// <summary>
        /// 更新部门的路径和层级信息
        /// </summary>
        /// <param name="deptId">部门ID</param>
        /// <returns>是否更新成功</returns>
        public async Task<bool> UpdateDeptPathAsync(Guid deptId)
        {
            var dept = await _terraDbContext.Depts.FindAsync(deptId);
            if (dept == null)
            {
                return false;
            }

            // 计算层级和路径
            int level = 1;
            string path = $"/{deptId}/";

            if (dept.ParentId.HasValue && dept.ParentId != Guid.Empty)
            {
                var parent = await _terraDbContext.Depts.FindAsync(dept.ParentId);
                if (parent != null)
                {
                    level = parent.Level + 1;
                    path = $"{parent.Path}{deptId}/";
                }
            }

            // 更新当前部门的层级和路径
            dept.Level = level;
            dept.Path = path;

            // 更新数据库
            _terraDbContext.Depts.Update(dept);
            await _terraDbContext.SaveChangesAsync();

            // 递归更新所有子部门
            await UpdateChildrenPathAsync(deptId, level, path);

            return true;
        }

        #endregion

        #region 私有辅助方法

        /// <summary>
        /// 递归更新子部门的路径和层级
        /// </summary>
        /// <param name="parentId">父部门ID</param>
        /// <param name="parentLevel">父部门层级</param>
        /// <param name="parentPath">父部门路径</param>
        /// <returns>异步任务</returns>
        private async Task UpdateChildrenPathAsync(Guid parentId, int parentLevel, string parentPath)
        {
            var children = await _terraDbContext.Depts.Where(d => d.ParentId == parentId).ToListAsync();

            foreach (var child in children)
            {
                int level = parentLevel + 1;
                string path = $"{parentPath}{child.Id}/";

                child.Level = level;
                child.Path = path;

                _terraDbContext.Depts.Update(child);

                // 递归处理子部门
                await UpdateChildrenPathAsync(child.Id, level, path);
            }

            await _terraDbContext.SaveChangesAsync();
        }

        #endregion
    }
}
